package cn.itcast.n8;

import java.util.*;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class TestGenericDao {
    public static void main(String[] args) {
        GenericDao dao = new GenericDaoCached();
        System.out.println("============> 查询");
        String sql = "select * from emp where empno = ?";
        int empno = 7369;
        Emp emp = dao.queryOne(Emp.class, sql, empno);
        System.out.println(emp);
        emp = dao.queryOne(Emp.class, sql, empno);
        System.out.println(emp);
        emp = dao.queryOne(Emp.class, sql, empno);
        System.out.println(emp);

        System.out.println("============> 更新");
        dao.update("update emp set sal = ? where empno = ?", 800, empno);
        emp = dao.queryOne(Emp.class, sql, empno);
        System.out.println(emp);
    }
}

class GenericDaoCached extends GenericDao{
    private GenericDao dao = new GenericDao();
    private Map<SqlPair,Object> map = new HashMap<>();
    private ReentrantReadWriteLock rw = new ReentrantReadWriteLock();


    @Override
    public <T> List<T> queryList(Class<T> beanClass, String sql, Object... args) {
        return dao.queryList(beanClass, sql, args);
    }

    @Override
    public <T> T queryOne(Class<T> beanClass, String sql, Object... args) {
        //查询缓存，直接返回
        rw.readLock().lock();
        final SqlPair key = new SqlPair(sql, args);
        try {
            final T value = (T) map.get(key);
            if (value!=null){
                return value;
            }
        } finally {
            rw.readLock().unlock();
        }

        rw.writeLock().lock();
        try {
            // 多个线程
            T value = (T) map.get(key);
            if (value == null){
                //缓存中没有，查询数据库
                value = dao.queryOne(beanClass, sql, args);
                map.put(key,value);
            }
            return value;
        } finally {
            rw.writeLock().unlock();
        }
    }

    @Override
    public int update(String sql, Object... args) {
        rw.writeLock().lock();
        try {
            //先更新数据库
            final int update = dao.update(sql, args);

            //再清缓存
            map.clear();
            return update;
        }finally {
            rw.writeLock().unlock();
        }
    }

    class SqlPair{
        private String sql;
        private Object[] args;

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            SqlPair sqlPair = (SqlPair) o;
            return Objects.equals(sql, sqlPair.sql) && Arrays.equals(args, sqlPair.args);
        }

        @Override
        public int hashCode() {
            int result = Objects.hash(sql);
            result = 31 * result + Arrays.hashCode(args);
            return result;
        }

        public SqlPair(String sql, Object[] args) {
            this.sql = sql;
            this.args = args;
        }
    }
}
//class GenericDaoCached extends GenericDao {
//    private GenericDao dao = new GenericDao();
//    private Map<SqlPair, Object> map = new HashMap<>();
//    private ReentrantReadWriteLock rw = new ReentrantReadWriteLock();
//
//    @Override
//    public <T> List<T> queryList(Class<T> beanClass, String sql, Object... args) {
//        return dao.queryList(beanClass, sql, args);
//    }
//
//    @Override
//    public <T> T queryOne(Class<T> beanClass, String sql, Object... args) {
//        // 先从缓存中找，找到直接返回
//        SqlPair key = new SqlPair(sql, args);;
//        rw.readLock().lock();
//        try {
//            T value = (T) map.get(key);
//            if(value != null) {
//                return value;
//            }
//        } finally {
//            rw.readLock().unlock();
//        }
//        rw.writeLock().lock();
//        try {
//            // 多个线程
//            T value = (T) map.get(key);
//            if(value == null) {
//                // 缓存中没有，查询数据库
//                value = dao.queryOne(beanClass, sql, args);
//                map.put(key, value);
//            }
//            return value;
//        } finally {
//            rw.writeLock().unlock();
//        }
//    }
//
//    @Override
//    public int update(String sql, Object... args) {
//        rw.writeLock().lock();
//        try {
//            // 先更新库
//            int update = dao.update(sql, args);
//            // 清空缓存
//            map.clear();
//            return update;
//        } finally {
//            rw.writeLock().unlock();
//        }
//    }
//
//    class SqlPair {
//        private String sql;
//        private Object[] args;
//
//        public SqlPair(String sql, Object[] args) {
//            this.sql = sql;
//            this.args = args;
//        }
//
//        @Override
//        public boolean equals(Object o) {
//            if (this == o) {
//                return true;
//            }
//            if (o == null || getClass() != o.getClass()) {
//                return false;
//            }
//            SqlPair sqlPair = (SqlPair) o;
//            return Objects.equals(sql, sqlPair.sql) &&
//                    Arrays.equals(args, sqlPair.args);
//        }
//
//        @Override
//        public int hashCode() {
//            int result = Objects.hash(sql);
//            result = 31 * result + Arrays.hashCode(args);
//            return result;
//        }
//    }
//
//}
